﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SlimDX;
using SlimDX.Direct3D9;

namespace Gype.UI.D3D9
{
    internal class TriangleProvider
    {
        public TriangleProvider(Rendertarget9 target)
        {
            mDevice = target.GraphicsDevice;
            mTarget = target;
            mVertexShader = new ShaderCompiler<VertexShader>(target.GraphicsDevice, Shaders.Triangle, "VertexMain", "vs_2_0");
            mPixelShader = new ShaderCompiler<PixelShader>(target.GraphicsDevice, Shaders.Triangle, "PixelMainFill", "ps_2_0");

            mTransformParam = mVertexShader.ConstantTable["transformMatrix"];
            mMatrixParam = mVertexShader.ConstantTable["orthoProjMatrix"];
            mViewportParam = mVertexShader.ConstantTable["viewportSize"];
            mBrushParam = mPixelShader.ConstantTable["brushSampler"];
            mViewportParamPixel = mPixelShader.ConstantTable["viewportSize"];
        }

        public void FillTriangles(Vector2[] points, Brush brush)
        {
            Vector2 minPos = new Vector2(float.MaxValue, float.MaxValue);
            Vector2 maxPos = new Vector2(float.MinValue, float.MinValue);

            foreach (var point in points)
            {
                if (point.X > maxPos.X)
                    maxPos.X = point.X;
                if (point.Y > maxPos.Y)
                    maxPos.Y = point.Y;
                if (point.X < minPos.X)
                    minPos.X = point.X;
                if (point.Y < minPos.Y)
                    minPos.Y = point.Y;
            }

            float lenX = maxPos.X - minPos.X;
            float lenY = maxPos.Y - minPos.Y;
            if(lenX == 0 || lenY == 0)
                throw new ArgumentException("Degenerated triangles not supported, use lines!");

            UIVertex[] triVertices = new UIVertex[points.Length];
            for (int i = 0; i < points.Length; ++i)
            {
                Vector2 v = points[i];

                triVertices[i] = new UIVertex()
                {
                    Position = new Vector3(v.X, v.Y, 0),
                    Color = -1,
                    TexCoord = new Vector2(v.X / lenX, v.Y / lenY)
                };
            }

            brush.ApplyToShader(mPixelShader, mBrushParam);

            mDevice.VertexShader = mVertexShader.Shader;
            mDevice.PixelShader = mPixelShader.Shader;

            mVertexShader.SetValue(mMatrixParam, mTarget.OrthoMatrix);
            mVertexShader.SetValue(mTransformParam, mTarget.Transform);
            mVertexShader.SetValue(mViewportParam, mTarget.Viewport);

            mPixelShader.SetValue(mViewportParamPixel, mTarget.Viewport);

            mDevice.VertexDeclaration = mTarget.UIVertexDeclaration;
            mDevice.DrawUserPrimitives(PrimitiveType.TriangleList, triVertices.Length / 3, triVertices);

            mDevice.VertexShader = null;
            mDevice.PixelShader = null;
        }

        private ShaderCompiler<VertexShader> mVertexShader;
        private ShaderCompiler<PixelShader> mPixelShader;
        private ConstantDescription mBrushParam;
        private ConstantDescription mMatrixParam;
        private ConstantDescription mTransformParam;
        private ConstantDescription mViewportParam;
        private ConstantDescription mViewportParamPixel;
        private Rendertarget9 mTarget;
        private Device mDevice;
    }
}
